package com.hup.utils.swing.model;

import com.hup.utils.commons.hardware.MouseUtil;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.awt.Component;
import java.awt.event.MouseEvent;
import java.util.ArrayList;

/**
 * 处理按钮[单选,多选]功能
 *
 * @author hugan
 * @date 2022/8/10
 */
@Slf4j
public class ButtonGroupMulti {

    /**
     * 当前选中的item,元素无重复的
     */
    @Getter
    private ArrayList<ButtonModelMulti> selections = new ArrayList<>();

    /**
     * 设置成单选
     *
     * @param model nullable
     */
    public void setSelection(ButtonModelMulti model) {
        selections.removeIf(selection -> {
            boolean remove = selection != model;
            if (remove) selection.setSelected(false);
            return remove;
        });
        if (model != null) {
            if (!selections.contains(model)) selections.add(model);
            model.setSelected(true);
        }
    }

    public void addSelection(ButtonModelMulti model) {
        if (!selections.contains(model)) selections.add(model);
        model.setSelected(true);
    }

    public void removeSelection(ButtonModelMulti model) {
        selections.remove(model);
        model.setSelected(false);
    }

    public void switchSelection(ButtonModelMulti model) {
        boolean selected = model.isSelected();
        if (selected) {
            selections.remove(model);
        } else {
            if (!selections.contains(model)) selections.add(model);
        }
        model.setSelected(!selected);
    }

    /**
     * 处理鼠标点击事件时的[选中状态]
     *
     * @param model 当前被点击的对象
     * @apiNote e.getSource必须符合:
     * .是 ButtonModelGetter
     * .存在parent, parent.getComponents() 都是e.getSource类型的对象,
     * .否则在处理shift事件时会有异常,或不能正确获取shift选区的起止index
     */
    public void mouseClicked(MouseEvent e, ButtonModelMulti model) {
        if (e.getClickCount() != 1) return;
        /*
        左
            有ctrl: 切换item选中状态
            有shift:详见下文注释
            无ctrl/shift: 选中item
        右
            无ctrl/shift:
                当前item已选中: 不处理, (外部-显示菜单)
                当前item未选中: 单选item, (外部-显示菜单)
            有ctrl/shift: 不处理, (外部-显示菜单)
         */
        if (MouseUtil.isLeftButton(e)) {
            if (e.isControlDown()) {
                switchSelection(model);
            } else if (e.isShiftDown()) {
                Object source = e.getSource();
                if (!(source instanceof ButtonModelGetter)) {
                    log.error("source不符合要求");
                    return;
                }
                if (selections.isEmpty()) {//首次选中
                    addSelection(model);
                } else {
                    /*
                    已有选中item
                    目标
                        选中[首次选中item, 当前item]之间的item
                    过程
                        .清空selections,除了第一项
                        .获取要选中的index范围
                        .更新选中item
                     */
                    for (int i = selections.size() - 1; i >= 1; i--) selections.remove(i).setSelected(false);
                    //
                    int indexCurrent = ((ButtonModelGetter) source).getModel().getComponentZOrder();
                    ButtonModelMulti firstSelected = selections.get(0);//第一个选中的item
                    int indexFirst = firstSelected.getComponentZOrder();
                    int indexSt = Math.min(indexCurrent, indexFirst);
                    int indexEd = Math.max(indexCurrent, indexFirst);
                    //log.info("indexCurrent, indexFirst=[{},{}]", indexCurrent, indexFirst);
                    //
                    Component[] components = model.getParent().getComponents();
                    for (int i = indexSt; i <= indexEd; i++) {
                        ButtonModelGetter getter = (ButtonModelGetter) components[i];
                        if (getter.getModel() != firstSelected) {
                            addSelection(getter.getModel());
                        }
                    }
                }
            } else {
                setSelection(model);
            }
        } else if (MouseUtil.isRightButton(e)) {
            if (!e.isControlDown() && !e.isShiftDown()) {
                if (!model.isSelected()) setSelection(model);
            }
        }
    }

    public interface ButtonModelGetter {
        ButtonModelMulti getModel();
    }

}
